package com.easepal7506a.project.observer;

import android.content.Context;
import android.net.wifi.ScanResult;
import android.os.Handler;
import android.util.Log;

import com.easepal.softaplib.BioClient;
import com.easepal.softaplib.IConnectListener;
import com.easepal.softaplib.wifi.WiFiManager;
import com.easepal7506a.project.manager.DataManager;
import com.easepal7506a.project.network.CommondManager;
import com.ogawa.base.callback.GetOnlineCallback;
import com.ogawa.base.network.BaseResponse;
import com.ogawa.base.network.bean.BeanOnline;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

import static com.ogawa.base.Constant.Constants.DEVICE_AP_FLITER;
import static com.ogawa.base.Constant.Constants.DEVICE_AP_IP;
import static com.ogawa.base.Constant.Constants.DEVICE_AP_PORT;

/**
 * 作者: bright.lin@medisana.net.cn
 * 时间: 2019/1/2
 * 标题: 配网Model层（8.0以上版本）
 * 描述: 配网功能Model层实现
 * 修改: 由 bright.lin@medisana.net.cn 修改于 2019/1/2
 */
public class SoftApNewModel {
    private static final String TAG = /*SoftApModel.class.getName()*/"TEST";

    // 动作成功
    public static final int ACTION_SUCCESS = 0;

    // 读取Sn码超时
    public static final int READ_SN_TIMEOUT = 3;
    // 连接Socket超时
    public static final int CONNECT_SOCKET_TIMEOUT = 4;
    // 扫描WIFI超时
    public static final int SCAN_AP_TIMEOUT = 5;
    // WIFI未打开
    public static final int ERROR_WIFI_DISABLED = 6;
    // Socket为空
    public static final int ERROR_SOCKET_NULL = 7;
    // Socket连接错误
    public static final int ERROR_SOCKET_FAILED = 8;
    // SSID错误
    public static final int ERROR_SSID_WRONG = 9;
    // SSID为空
    public static final int ERROR_SSID_NULL = 10;

    // 扫描WIFI超时时长
    private static final int SCAN_TIMEOUT_TIME = 10000;
    // 连接设备热点超时时长
    private static final int SOCKET_TIMEOUT_TIME = 10000;
    // 读取Sn码超时时长
    private static final int SN_TIMEOUT_TIME = 60000;
    // http请求重试间隔
    private static final int HTTP_RETRY_INTERVAL = 2000;

    // 上下文
    private Context mContext;

    // BIO的Socket客户端
    private BioClient bioClient;

    // WIFI的ScanResult对象
    private ScanResult wifi = null;
    // WIFI的密码
    private String psw = null;
    // 设备的MAC地址
    private String deviceMac = null;

    // 是否扫描WIFI中标志位
    private boolean isScanning = false;
    // 是否建立Socket连接中标志位
    private boolean isConnectingSocket = false;
    // 是否读取Sn码中标志位
    private boolean isReadingSn = false;
    // Socket连接重试次数
    private int socketRetryCount = 5;

    // WIFI的ScanResult对象列表
    private List<ScanResult> wifiResults = new ArrayList<>();

    // 扫描WIFI回调
    private ScanApListener scanApListener;
    // Socket动作回调
    private SocketListener socketListener;
    // 读取Sn码回调
    private ReadSnListener readSnListener;

    // Socket连接回调接口
    private IConnectListener connectListener = new IConnectListener() {

        @Override
        public void onConnectionSuccess() {
            if (isConnectingSocket) {
                isConnectingSocket = false;
                setDeviceNetwork();
            }
        }

        @Override
        public void onConnectionFailed() {
            Log.d(TAG, "onConnectionFailed-> isConnectingSocket:" + isConnectingSocket + " isReadingSn:" + isReadingSn);
            if (isConnectingSocket) {
                if (socketRetryCount > 0) {
                    socketRetryCount--;
                    reconnectSocket();
                } else {
                    mHandler.removeMessages(CONNECT_SOCKET_TIMEOUT);
                    onSocketFailure(ERROR_SOCKET_FAILED);
                }
            }
        }

        @Override
        public void onMessage(byte[] bytes) {
            parseMessage(bytes);
        }
    };

    // 按摩椅在线事件的回调接口
    private GetOnlineCallback getOnlineCallback = new GetOnlineCallback() {
        @Override
        public void onGetOnlineSuccess(BaseResponse<BeanOnline> program) {
            if (null != program && null != program.getData() && null != program.getData().getSn()) {
                DataManager.getInst().setmSn(program.getData().getSn());
                Log.d(TAG, "onGetOnlineSuccess:" + program.getData().getSn());
                DataManager.getInst().setConnectSocket(false);
                SoftApSucceedObserver.getInst().noticeSoftApOk();
                onReadSnSuccess();
            } else {
                Log.d(TAG, "onGetOnlineFailure null data");
                retryOnline();
            }
        }

        @Override
        public void onGetOnlineFailure() {
            Log.d(TAG, "onGetOnlineFailure");
            retryOnline();
        }
    };

    // 消息处理
    private Handler mHandler = new Handler(msg -> {
        switch (msg.what) {
            case SCAN_AP_TIMEOUT:
                onScanFailure(SCAN_AP_TIMEOUT);
                break;
            case CONNECT_SOCKET_TIMEOUT:
                onSocketFailure(CONNECT_SOCKET_TIMEOUT);
                break;
            case READ_SN_TIMEOUT:
                onReadSnFailure(READ_SN_TIMEOUT);
                break;
        }
        return false;
    }
    );

    /**
     * 带参构造器
     *
     * @param context 上下文
     */
    public SoftApNewModel(Context context) {
        mContext = context;
        WiFiManager.getInstance(mContext).registerBroadcastReceivers(context);
        WiFiManager.getInstance(mContext).setOnWifiScanResultsListener(scanResults -> {
            if (isScanning) {
                handleScanResults(scanResults);
                onScanSuccess();
            }
        });
    }

    /**
     * 释放资源
     */
    public void onDestroy() {
        if (null != getOnlineCallback) {
            getOnlineCallback = null;
        }
        if (null != connectListener) {
            connectListener = null;
        }
        if (null != mHandler) {
            mHandler.removeCallbacksAndMessages(null);
        }
        if (null != bioClient) {
            bioClient.disconnect();
            bioClient = null;
        }
        WiFiManager.getInstance(mContext).onDestory(mContext);
    }

    /**
     * 开始扫描WIFI
     *
     * @param scanApListener 扫描WIFI回调
     */
    public void startScan(ScanApListener scanApListener) {
        this.scanApListener = scanApListener;
        if (isWifiDisabled()) {
            onScanFailure(ERROR_WIFI_DISABLED);
            return;
        }
        if (!isScanning) {
            isScanning = true;
            WiFiManager.getInstance(mContext).startScan();
            mHandler.sendEmptyMessageDelayed(SCAN_AP_TIMEOUT, SCAN_TIMEOUT_TIME);
        }
    }

    /**
     * 获取WIFI的ScanResult对象列表
     *
     * @return WIFI的ScanResult对象列表
     */
    public List<ScanResult> getWifiResults() {
        return wifiResults;
    }

    /**
     * 设置WIFI的ScanResult对象
     * @param scanResult WIFI的ScanResult对象
     */
    public void setWifiScanResult(ScanResult scanResult) {
        wifi = scanResult;
    }

    /**
     * 设置WIFI密码
     * @param psw WIFI密码
     */
    public void setWifiPassword(String psw) {
        this.psw = psw;
    }

    /**
     * 与设备热点建立Socket连接
     * @param socketListener Socket动作回调
     */
    public void connectSocket(SocketListener socketListener) {
        this.socketListener = socketListener;
        if (isWifiDisabled()) {
            onSocketFailure(ERROR_WIFI_DISABLED);
            return;
        }

        String ssid = null;
        if (null != WiFiManager.getInstance(mContext).getConnectionInfo()) {
            ssid = WiFiManager.getInstance(mContext).getConnectionInfo().getSSID();
        }
        if (ssid == null || !ssid.contains(DEVICE_AP_FLITER)) {
            onSocketFailure(ERROR_SSID_WRONG);
            return;
        }

        if (null == wifi) {
            onSocketFailure(ERROR_SSID_NULL);
            return;
        }

        connectSocket();
    }

    /**
     * 读取Sn码
     * @param readSnListener 读取Sn码回调
     */
    public void getSn(ReadSnListener readSnListener) {
        this.readSnListener = readSnListener;
        if (isWifiDisabled()) {
            onReadSnFailure(ERROR_WIFI_DISABLED);
            return;
        }
        isReadingSn = true;
        getOnline();
        mHandler.sendEmptyMessageDelayed(READ_SN_TIMEOUT, SN_TIMEOUT_TIME);
    }

    /**
     * 判断WIFI开关是否关闭
     * @return true-关闭/false-打开
     */
    private boolean isWifiDisabled() {
        return !WiFiManager.getInstance(mContext).isWifiEnabled();
    }

    /**
     * 处理WIFI扫描结果
     * @param scanResults WIFI扫描结果ScanResult对象列表
     */
    private void handleScanResults(List<ScanResult> scanResults) {
        if (null != scanResults && scanResults.size() > 0) {
            wifiResults.clear();
            for (ScanResult scanResult : scanResults) {
                Log.d(TAG, "handleScanResults:" + scanResult.SSID);
                if (scanResult.SSID.contains(DEVICE_AP_FLITER) && scanResult.SSID.length() == 10) {
                    continue;
                }
                wifiResults.add(scanResult);
            }
        }
    }

    /**
     * 连接Socket
     */
    private void connectSocket() {
        closeSocket();
        newSocket();
        Log.d(TAG, "connectSocket->isConnectingSocket:" + isConnectingSocket);
        if (null != bioClient && !isConnectingSocket) {
            Log.d(TAG, "connectSocket->isConnectingSocket:start");
            isConnectingSocket = true;
            bioClient.connect();
            socketRetryCount = 5;
            mHandler.sendEmptyMessageDelayed(CONNECT_SOCKET_TIMEOUT, SOCKET_TIMEOUT_TIME);
        } else {
            onSocketFailure(ERROR_SOCKET_NULL);
        }
    }

    /**
     * 重连Socket
     */
    private void reconnectSocket() {
        if (null != bioClient) {
            Log.d(TAG, "reconnectSocket->start");
            bioClient.reconnect();
        } else {
            Log.d(TAG, "reconnectSocket->end");
            mHandler.removeMessages(CONNECT_SOCKET_TIMEOUT);
            onSocketFailure(ERROR_SOCKET_NULL);
        }
    }

    /**
     * 新建Socket客户端对象
     */
    private void newSocket() {
        if (null == bioClient) {
            bioClient = new BioClient(connectListener);
            bioClient.setConnectAddress(DEVICE_AP_IP, DEVICE_AP_PORT);
            Log.d(TAG, "connectSocket->new Socket");
        }
    }

    /**
     * 关闭Socket连接
     */
    private void closeSocket() {
        if (null != bioClient) {
            bioClient.disconnect();
            bioClient = null;
            Log.d(TAG, "bioClient is null");
        }
    }

    /**
     * 发送WIFI账号密码至设备
     * ','使用'\,'表示，'$'使用'\$'表示，'\'使用'\\'表示。AT指令中作为参数分隔符的','、'$'不进行转义
     */
    private void setDeviceNetwork() {
        if (null != bioClient) {
            String ssid = wifi.SSID;
            String mpsw = psw;
            ssid = ssid.replace("\\", "\\\\");
            ssid = ssid.replace(",", "\\,");
            ssid = ssid.replace("$", "\\$");

            mpsw = mpsw.replace("\\", "\\\\");
            mpsw = mpsw.replace(",", "\\,");
            mpsw = mpsw.replace("$", "\\$");
            String msg = "AT+SETWLAN=" + ssid + "," + mpsw + "$";
            bioClient.sendMsg(msg);
        } else {
            mHandler.removeMessages(CONNECT_SOCKET_TIMEOUT);
            onSocketFailure(ERROR_SOCKET_NULL);
        }
    }

    /**
     * 获取设备MAC地址
     */
    private void getDeviceMac() {
        if (null != bioClient) {
            String msg = "AT+GETMAC";
            bioClient.sendMsg(msg);
        } else {
            mHandler.removeMessages(CONNECT_SOCKET_TIMEOUT);
            onSocketFailure(ERROR_SOCKET_NULL);
        }
    }

    /**
     * 解析设备发来的信息
     * @param bytes 字节数组
     */
    private void parseMessage(byte[] bytes) {
        String s = new String(bytes);
        Log.d(TAG, "parseMessage:" + s);
        if (s.contains("OK")) {
            getDeviceMac();
        } else {
            String mac = bytesToHexString(bytes);
            if (null != mac && mac.length() == 12) {
                Log.d(TAG, "parseMessage->mac:" + mac);
                deviceMac = mac.toUpperCase();
                closeSocket();
                onSocketSuccess();
            }
        }
    }

    /**
     * 查询设备在线状态（获取Sn码）
     */
    private void getOnline() {
        CommondManager.getInst().getOnline(mContext, deviceMac, 1, getOnlineCallback);
    }

    /**
     * 重试查询设备在线状态（获取Sn码）
     */
    private void retryOnline() {
        Log.e("retryOnline", isReadingSn + "");
        if (!isReadingSn) return;
        Observable.timer(HTTP_RETRY_INTERVAL, TimeUnit.MILLISECONDS)
                .observeOn(Schedulers.io())
                .subscribe(new Observer<Long>() {
                    Disposable d;

                    @Override
                    public void onSubscribe(Disposable d) {
                        this.d = d;
                    }

                    @Override
                    public void onNext(Long aLong) {
                        getOnline();
                        d.dispose();
                    }

                    @Override
                    public void onError(Throwable e) {
                        d.dispose();
                    }

                    @Override
                    public void onComplete() {
                        d.dispose();
                    }
                });
    }

    /**
     * 字节数组转为16进制样式字符串
     * @param src 字节数组
     * @return 16进制样式字符串
     */
    private String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }

        for (byte b : src) {
            int v = b & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }

        return stringBuilder.toString();
    }

    /**
     * 扫描WIFI成功
     */
    private void onScanSuccess() {
        isScanning = false;
        mHandler.removeMessages(SCAN_AP_TIMEOUT);
        if (null != scanApListener) {
            scanApListener.onSuccess();
        }
    }

    /**
     * 扫描WIFI失败
     * @param errorCode 错误码
     */
    private void onScanFailure(int errorCode) {
        isScanning = false;
        if (null != scanApListener) {
            scanApListener.onFailure(errorCode);
        }
    }

    /**
     * 与设备建立Socket连接成功
     */
    private void onSocketSuccess() {
        isConnectingSocket = false;
        mHandler.removeMessages(CONNECT_SOCKET_TIMEOUT);
        if (null != socketListener) {
            socketListener.onSuccess();
        }
    }

    /**
     * 与设备建立Socket连接失败
     * @param errorCode 错误码
     */
    private void onSocketFailure(int errorCode) {
        isConnectingSocket = false;
        if (null != socketListener) {
            socketListener.onFailure(errorCode);
        }
    }

    /**
     * 读取Sn码成功
     */
    private void onReadSnSuccess() {
        isReadingSn = false;
        mHandler.removeMessages(READ_SN_TIMEOUT);
        if (null != readSnListener) {
            readSnListener.onSuccess();
        }
    }

    /**
     * 读取Sn码失败
     * @param errorCode 错误码
     */
    private void onReadSnFailure(int errorCode) {
        isReadingSn = false;
        if (null != readSnListener) {
            readSnListener.onFailure(errorCode);
        }
    }

    /**
     * 扫描WIFI回调接口
     */
    public interface ScanApListener {
        void onSuccess();

        void onFailure(int errorCode);
    }

    /**
     * Socket动作回调接口
     */
    public interface SocketListener {
        void onSuccess();

        void onFailure(int errorCode);
    }

    /**
     * 读取Sn码回调接口
     */
    public interface ReadSnListener {
        void onSuccess();

        void onFailure(int errorCode);
    }
}
